#include "EventLoop.hpp"
#include "Acceptor.hpp"
#include "MutexLock.hpp"
#include "TcpConnection.hpp"
#include "header.h"

#include <sys/epoll.h>
#include <sys/eventfd.h>

namespace wd
{

EventLoop::EventLoop(Acceptor & acceptor)
: _epfd(createEpollFd())
, _eventfd(createEventfd())
, _isLooping(false)
, _acceptor(acceptor)
, _evtArr(1000)
{
    addEpollReadEvent(_eventfd);
    addEpollReadEvent(_acceptor.fd());
}

EventLoop::~EventLoop()
{
    close(_epfd);
    close(_eventfd);
}

void EventLoop::loop()
{
    _isLooping = true;

    while(_isLooping)
    {
        waitEpollFd();
    }
}

// 要与 loop 函数运行在不用的线程
void EventLoop::unloop()
{
    _isLooping = false;
}

void EventLoop::runInLoop(Functor && cb)
{
    {
        // 多线程环境之下要加锁
        MutexLockGuard autolock(_mutex);
        _pendingFunctors.push_back(cb);
    }
    // 通知 IO 线程发送数据
    wakeup();
}

void EventLoop::waitEpollFd()
{
    // epoll_wait
    int nready = epoll_wait(_epfd , _evtArr.data() , _evtArr.size() , 5000);

    if(nready == -1 && errno == EINTR)
    {
        return;
    }
    else if(nready == -1)
    {
        perror("epoll_wait");
        exit(EXIT_FAILURE);
    }
    else if(nready == 0)
    {
        printf("epoll连接超时！\n");
    }
    // nready > 0
    else
    {
        for(int i = 0 ; i < nready ; ++i)
        {
            int fd = _evtArr[i].data.fd;

            if(fd == _acceptor.fd())
            {
                handleNewConnection();
            }
            else if(fd == _eventfd)
            {
                handleReadEvent();
                doPendingFunctors();
            }
            else
            {
                handleMessage(fd);
            }
        }
    }
}

void EventLoop::handleNewConnection()
{
    // 获取新连接
    int netfd = _acceptor.accept();
    // epoll 添加对于 epoll 的监听
    addEpollReadEvent(netfd);
    // 创建 TcpConnection 对象
    TcpConnectionPtr conn(new TcpConnection(netfd , this));
    // 设置三个函数对象
    conn -> setAllCallbacks(
                            _onConnection , 
                            _onMessage , 
                            _onClose
                           );
    // 添加到容器 map
    _conns.insert(std::make_pair(netfd , conn));
    // 调用连接建立时的函数对象
    conn -> handleNewConnectionCallback();
}

void EventLoop::handleMessage(int fd)
{
    // 先通过 fd 查找到 TcpConnection 对象
    auto iter = _conns.find(fd);

    if(iter != _conns.end())
    {
        //判断连接是否断开
        bool isClosed = iter -> second -> isClosed();

        if(isClosed)
        {
            // 连接断开，调用连接断开时的函数对象
            iter -> second ->handleCloseCallback();
            // 从 epoll 的监听红黑树上删除
            delEpollReadEvent(fd);
            // 从 map 中删除
            _conns.erase(fd);
        }
        else
        {
            // 发送消息过来，开始要调用消息到达时的函数对象
            iter -> second -> handleMessageCallback();
        }
    }
}

int EventLoop::createEpollFd()
{
    int fd = epoll_create1(0);

    if(fd < 0)
    {
        perror("epoll_create1");
    }

    return fd;
}

void EventLoop::addEpollReadEvent(int fd)
{
    struct epoll_event ev;
    memset(&ev , 0 , sizeof(ev));
    ev.data.fd = fd;
    ev.events = EPOLLIN;

    int ret = epoll_ctl(_epfd , EPOLL_CTL_ADD , fd , &ev);

    if(ret < 0)
    {
        perror("epoll_ctl");
    }
}

void EventLoop::delEpollReadEvent(int fd)
{
    struct epoll_event ev;
    memset(&ev , 0 , sizeof(ev));
    ev.data.fd = fd;

    int ret = epoll_ctl(_epfd , EPOLL_CTL_DEL , fd , &ev);

    if(ret < 0)
    {
        perror("epoll_ctl");
    }
}

int EventLoop::createEventfd()
{
    int fd = eventfd(0 ,0);

    if(fd < 0)
    {
        perror("eventfd");
    }
    return fd;
}

// 处理内核计算器的值（清零）
void EventLoop::handleReadEvent()
{
    uint64_t howmany = 0;
    int ret = read(_eventfd , &howmany , sizeof(howmany));
    
    printf("\nhowmany: %ld\n" , howmany);

    if(ret != sizeof(howmany))
    {
        perror("read");
    }
}

void EventLoop::wakeup()
{
    uint64_t one = 1;
    int ret = write(_eventfd , &one , sizeof(one));

    if(ret != sizeof(one))
    {
        perror("write");
    }
}

void EventLoop::doPendingFunctors()
{
    printf(">>> doPendingFunctors\n");

    vector<Functor> tmp;
    {
        // 使用语句块，减小加锁范围
        MutexLockGuard autolock(_mutex);
        tmp.swap(_pendingFunctors);
    }

    // 经过交换，_pendingFunctors 被解放出来了
    // 其他的计算线程可以对它进行修改操作
    for (auto & f : tmp)
    {
        f();
    }
}

} // end of namespace wd
